#include "stdlib.hpp"
#include <purewell/types.hpp>
#include <purewell/file.hpp>
#include <purewell/system.hpp>

#include "libfile.hpp"

namespace purewell
{

PWFile::PWFile() : m_fd(-1)
{
}

PWFile::~PWFile()
{
	int fd(detach());
	if ( -1 != fd )
	{
		::close(fd);
	}
}

void
PWFile::onEvent(PWIOPoll* io, int fd, int event)
{
	fprintf(stderr, "PWFile::onEvent(%p, %d)\n",
		io, event);
}

void
PWFile::destroy(void)
{
	int fd(detach());
	if ( -1 != fd )
	{
		::close(fd);
	}
}

bool
PWFile::attach(int fd)
{
	m_fd = fd;
	return true;
}

int
PWFile::detach(void)
{
	int fd(m_fd);
	m_fd = -1;
	return fd;
}

ssize_t
PWFile::read(void* buf, size_t blen)
{
	return ::read(m_fd, (char*)buf, blen);
}

ssize_t
PWFile::write(const void* buf, size_t blen)
{
	return ::write(m_fd, (const char*)buf, blen);
}

bool
PWFile::setModeBlock(bool block)
{
	return __PWSetFlags(!block, m_fd, O_NONBLOCK);
}

bool
PWFile::getModeBlock(bool& block) const
{
	if ( !__PWGetFlags(block, m_fd, O_NONBLOCK) )
	{
		return false;
	}

	block = !block;
	return true;
}

bool
PWFile::setModeAsync(bool async)
{
	return __PWSetFlags(async, m_fd, O_ASYNC);
}

bool
PWFile::getModeAsync(bool& async) const
{
	return __PWGetFlags(async, m_fd, O_ASYNC);
}

bool
PWFile::setModeCloseOnExec(bool coe)
{
	return __PWSetFDFlags(coe, m_fd, FD_CLOEXEC);
}

bool
PWFile::getModeCloseOnExec(bool& coe) const
{
	return __PWGetFDFlags(coe, m_fd, FD_CLOEXEC);
}

bool
PWFile::getMode(int& mode) const
{
	int res(fcntl(m_fd, F_GETFL));
	if ( -1 == res )
	{
		return false;
	}

	mode = res;
	return true;
}

bool
PWFile::setMode(int mode)
{
	return 0 == fcntl(m_fd, F_SETFL, mode);
}

bool
PWFile::duplicate(int srcfd)
{
	int dfd(dup(srcfd));
	if ( -1 == dfd ) return false;

	bool res(attach(dfd));
	if ( false == res )
	{
		::close(dfd);
	}

	return res;
}

bool
PWFile::duplicate(int srcfd, int newfd)
{
	int dfd(dup2(srcfd, newfd));
	if ( -1 == dfd ) return false;

	bool res(attach(dfd));
	if ( false == res )
	{
		::close(dfd);
	}

	return res;
}

ssize_t
PWFile::readParallel(void* buf, size_t blen, off_t offset)
{
#if (_XOPEN_SOURCE - 0 ) >= 500
	return ( ::pread(m_fd, buf, blen, offset) );
#else
	__PWERRNO_NOIMPL();
	return -1;
#endif
}

ssize_t
PWFile::writeParallel(const void* buf, size_t blen, off_t offset)
{
#if (_XOPEN_SOURCE - 0 ) >= 500
	return ( ::pwrite(m_fd, buf, blen, offset) );
#else
	__PWERRNO_NOIMPL();
	return -1;
#endif
}

PWNamedFile::PWNamedFile()
{
}

PWNamedFile::~PWNamedFile()
{
}

bool
PWNamedFile::initialize(const char* name, int omode, int perm)
{
	std::string _name;
	PWSystem::getInstance().getCurrentDirectory(_name);
	if ( _name.empty() ) return false;
	_name.append(PWDIR_DELIMITER);
	_name.append(name);

	const int fd(open(name, omode, perm));
	if ( -1 == fd ) return false;

	m_name.swap(_name);
	m_fd = fd;

	return true;
}

const char*
PWNamedFile::getName(void) const
{
	return m_name.c_str();
}

bool
PWNamedFile::unlink(void)
{
	const bool res(0 == ::unlink(m_name.c_str()));
	if ( res )
	{
		m_name.clear();
	}

	return res;
}

int
PWNamedFile::detach(void)
{
	int fd(m_fd);
	m_name.clear();
	m_fd = -1;
	return fd;
}

};//namespace purewell

